# -*- python -*-
# ex: set syntax=python:

# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# It has one job: define a dictionary named BuildmasterConfig. This
# dictionary has a variety of keys to control different aspects of the
# buildmaster. They are documented in docs/config.xhtml .

from buildbot.scheduler import Dependent
from buildbot.scheduler import Scheduler
from buildbot.schedulers import triggerable

from master import build_utils
from master import master_utils
from master import slaves_list
from master import status_logger
from master import pubsub_json_status_push
from master.factory import annotator_factory
from master.factory.dart import dart_factory
from master.factory.dart.dart_factory import (linux_env, windows_env,
    linux_clang_env, linux_asan_env_32, linux_asan_env_64)
from master.factory.dart.channels import CHANNELS

from twisted.python import log

import config
import master_site_config
ActiveMaster = master_site_config.Dart
utils = dart_factory.DartUtils(ActiveMaster)

# Hack to increase timeout for steps, dart2js debug checked mode takes more
# than 8 hours.
utils.monkey_patch_remoteshell()

MASTER_HOST = ActiveMaster.master_host
WEB_STATUS = True
MAIL_NOTIFIER = ActiveMaster.is_production_host
GOOD_REVISIONS = ActiveMaster.is_production_host

# This is the dictionary that the buildmaster pays attention to. We also use
# a shorter alias to save typing.
c = BuildmasterConfig = {}

config.DatabaseSetup(c)

# 'slavePortnum' defines the TCP port to listen on. This must match the value
# configured into the buildslaves (with their --master option)
c['slavePortnum'] = ActiveMaster.slave_port

slaves = slaves_list.SlavesList('slaves.cfg', 'Dart')

annotator = annotator_factory.AnnotatorFactory()

def setup_channel(channel):
  postfix = channel.builder_postfix

  ####### Variant definitions
  # build-base-name, category, platform, builder, tester
  # env are relative to the dart root directory.

  def category(name):
    return '%d%s%s|all' % (channel.position, name, channel.category_postfix)

  # Add recipe-based dart builders and testers
  variants_recipe_special_trigger = [
    {
      'name': 'target-arm-vm-linux-release' + postfix,
      'category': category('1vm-misc'),
      'factory_builder': annotator.BaseFactory(
          recipe='dart/dart_cross_tester'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'dart2js-linux-drt-1-2' + postfix,
      'category': category('8chrome'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart2js_nobuild'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'dart2js-linux-drt-2-2' + postfix,
      'category': category('8chrome'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart2js_nobuild'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'dart2js-linux-drt-csp-minified' + postfix,
      'category': category('8chrome'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart2js_nobuild'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'dart2js-mac10.11-safari-1-3' + postfix,
      'builddir': '10.11-1' + postfix,
      'category': category('90safari'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart2js_nobuild'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'dart2js-mac10.11-safari-2-3' + postfix,
      'builddir': '10.11-2' + postfix,
      'category': category('90safari'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart2js_nobuild'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'dart2js-mac10.11-safari-3-3' + postfix,
      'builddir': '10.11-3' + postfix,
      'category': category('90safari'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart2js_nobuild'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'dart2js-mac10.11-chrome' + postfix,
      'builddir': '10.11-c' + postfix,
      'category': category('8chrome'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart2js_nobuild'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'pkg-mac10.11-release' + postfix,
      'builddir': 'pmr' + postfix,
      'category': category('94pub-pkg'),
      'factory_builder': annotator.BaseFactory(recipe='dart/packages'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'pkg-linux-release' + postfix,
      'category': category('94pub-pkg'),
      'platform': 'posix' + postfix,
      'factory_builder': annotator.BaseFactory(recipe='dart/packages'),
      'env': linux_env,
    },
    {
      'name': 'pkg-win7-release' + postfix,
      'category': category('94pub-pkg'),
      'platform': 'windows' + postfix,
      'factory_builder': annotator.BaseFactory(recipe='dart/packages'),
      'env': windows_env,
      'auto_reboot': True,
    },
    {
      'name': 'analyze-linux' + postfix,
      'category': category('30analyzer'),
      'factory_builder': annotator.BaseFactory(
          recipe='dart/misc_nobuild'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'analyzer-mac10.11-release' + postfix,
      'builddir': 'azr' + postfix,
      'category': category('30analyzer'),
      'platform': 'posix' + postfix,
      'factory_builder': annotator.BaseFactory(recipe='dart/packages'),
    },
    {
      'name': 'analyzer-linux-release' + postfix,
      'category': category('30analyzer'),
      'platform': 'posix' + postfix,
      'factory_builder': annotator.BaseFactory(recipe='dart/packages'),
      'env': linux_env,
    },
    {
      'name': 'analyzer-win7-release' + postfix,
      'category': category('30analyzer'),
      'platform': 'windows' + postfix,
      'factory_builder': annotator.BaseFactory(recipe='dart/packages'),
      'env': windows_env,
    },
    {
      'name': 'analyzer-mac10.11-release-strong' + postfix,
      'builddir': 'azrs' + postfix,
      'category': category('30analyzer'),
      'platform': 'posix' + postfix,
      'factory_builder': annotator.BaseFactory(recipe='dart/packages'),
    },
    {
      'name': 'analyzer-linux-release-strong' + postfix,
      'category': category('30analyzer'),
      'platform': 'posix' + postfix,
      'factory_builder': annotator.BaseFactory(recipe='dart/packages'),
      'env': linux_env,
    },
    {
      'name': 'analyzer-win7-release-strong' + postfix,
      'category': category('30analyzer'),
      'platform': 'windows' + postfix,
      'factory_builder': annotator.BaseFactory(recipe='dart/packages'),
      'env': windows_env,
    },
  ]

  for shard in range(1,6):
    variants_recipe_special_trigger.append({
      'name': ('dart2js-linux-d8-minified-%s-5' % shard) + postfix,
      'category': category('20dart2js-d8-minified'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart2js_nobuild'),
      'platform': 'posix' + postfix,
    })

  for shard in range(1,5):
    variants_recipe_special_trigger.append({
      'name': ('dart2js-linux-jsshell-%s-4' % shard) + postfix,
      'category': category('23dart2js-jsshell'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart2js_nobuild'),
      'platform': 'posix' + postfix,
    })

  for shard in range(1,5):
    variants_recipe_special_trigger.append({
      'name': ('dart2js-linux-chromeff-%s-4' % shard) + postfix,
      'category': category('7dart2js-linux'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart2js_nobuild'),
      'platform': 'posix' + postfix,
    })

  for browser in ['win8-ie11', 'win7-chrome', 'win7-ie11ff']:
    for shard in range(1,5):
      builddir = '%s_%s' % (browser[-2:], shard)
      variants_recipe_special_trigger.append({
        'name': ('dart2js-%s-%s-4' % (browser, shard)) + postfix,
        'category': category('92dart2js-windows'),
        'factory_builder': annotator.BaseFactory(recipe='dart/dart2js_nobuild'),
        'platform': 'windows' + postfix,
        'builddir': builddir + postfix,
      })

  variants_vm_recipe = [
    {
      'name': 'dart-sdk-linux' + postfix,
      'category': category('4dart-sdk'),
      'platform': 'posix' + postfix,
      'factory_builder': annotator.BaseFactory(recipe='dart/sdk_builder'),
      'env': linux_env,
    },
    {
      'name': 'dart-sdk-windows' + postfix,
      'category': category('4dart-sdk'),
      'platform': 'windows' + postfix,
      'factory_builder': annotator.BaseFactory(recipe='dart/sdk_builder'),
      'env': windows_env,
    },
    {
      'name': 'dart-sdk-mac' + postfix,
      'category': category('4dart-sdk'),
      'factory_builder': annotator.BaseFactory(recipe='dart/sdk_builder'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'vm-win-debug-ia32-russian' + postfix,
      'category': category('1vm-misc'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
      'platform': 'windows' + postfix,
    },
    {
      'name': 'vm-linux-product-x64' + postfix,
      'category': category('1vm-product'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'vm-win-product-x64' + postfix,
      'category': category('1vm-product'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
      'platform': 'windows' + postfix,
    },
    {
      'name': 'vm-mac-product-x64' + postfix,
      'category': category('1vm-product'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'vm-mac-debug-simdbc64' + postfix,
      'category': category('1vm'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'vm-mac-release-simdbc64' + postfix,
      'category': category('1vm'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'vm-noopt-simarm64-mac' + postfix,
      'category': category('1vm-precomp'),
      'factory_builder': annotator.BaseFactory(
          recipe='dart/dart',
          factory_properties={
              'target_arch': 'simarm64',
              'build_targets': ['runtime_precompiled'],
              'test_args': ['-cprecompiler', '-rdart_precompiled', '--use-blobs']}),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'vm-precomp-android-release-1-3' + postfix,
      'category': category('1vm-precomp'),
      'factory_builder': annotator.BaseFactory(
          recipe='dart/dart',
          factory_properties={
            'target_arch': 'arm',
            'build_args': ['--os=android'],
            'build_targets': ['runtime_precompiled'],
            'test_args': ['-cprecompiler', '-rdart_precompiled',
                          '--system=android',
                          '--use-blobs',
                          '--shard=1',
                          '--shards=3']}),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'vm-precomp-android-release-2-3' + postfix,
      'category': category('1vm-precomp'),
      'factory_builder': annotator.BaseFactory(
          recipe='dart/dart',
          factory_properties={
            'target_arch': 'arm',
            'build_args': ['--os=android'],
            'build_targets': ['runtime_precompiled'],
            'test_args': ['-cprecompiler', '-rdart_precompiled',
                          '--system=android',
                          '--use-blobs',
                          '--shard=2',
                          '--shards=3']}),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'vm-precomp-android-release-3-3' + postfix,
      'category': category('1vm-precomp'),
      'factory_builder': annotator.BaseFactory(
          recipe='dart/dart',
          factory_properties={
            'target_arch': 'arm',
            'build_args': ['--os=android'],
            'build_targets': ['runtime_precompiled'],
            'test_args': ['-cprecompiler', '-rdart_precompiled',
                          '--system=android',
                          '--use-blobs',
                          '--shard=3',
                          '--shards=3']}),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'cross-arm-vm-linux-release' + postfix,
      'category': category('1vm-misc'),
      'factory_builder': annotator.BaseFactory(
          recipe='dart/dart_cross_compiler'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'versionchecker-linux' + postfix,
      'category': category('99misc'),
      'factory_builder': annotator.BaseFactory(recipe='dart/misc'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'debianpackage-linux' + postfix,
      'category': category('99misc'),
      'factory_builder': annotator.BaseFactory(recipe='dart/misc'),
      'platform': 'posix' + postfix,
    }
  ]

  # VM Kernel
  variants_kernel_recipe = [ ]

  for platform in ['linux']:
    for arch in ['x64']:
      for mode in ['release', 'debug']:
        variants_kernel_recipe.append({
            'name': 'vm-kernel-%s-%s-%s' % (platform, mode, arch) + postfix,
            'category': category('1vm-kernel'),
            'factory_builder':
                annotator.BaseFactory(recipe='dart/dart_vm_kernel'),
            'platform': 'posix',
        })

  for platform in ['linux', 'mac', 'win']:
    for arch in ['x64', 'ia32']:
      for mode in ['debug', 'release']:
        variants_vm_recipe.append({
          'name': 'vm-%s-%s-%s' % (platform, mode, arch) + postfix,
          'category': category('1vm'),
          'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
          'platform': ('windows' if platform == 'win' else 'posix') + postfix
        })

  for arch in ['simmips', 'simarm', 'simarm64']:
    for mode in ['debug', 'release']:
      if arch == 'simarm64' and mode == 'debug': continue
      variants_vm_recipe.append({
        'name': 'vm-linux-%s-%s' % (mode, arch) + postfix,
        'category': category('1vm'),
        'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
        'platform': 'posix' + postfix
      })

  for type in ['asan', 'optcounter-threshold']:
    for arch in ['ia32', 'x64']:
      variants_vm_recipe.append({
        'name': 'vm-linux-release-%s-%s' % (arch, type) + postfix,
        'category': category('1vm-misc'),
        'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
        'platform': 'posix' + postfix
      })

  for runtime in ['app', 'precomp']:
    for mode in ['debug', 'release', 'product']:
      if runtime == 'precomp' and mode == 'release': continue
      variants_vm_recipe.append({
        'name': ('%s-linux-%s-x64' % (runtime, mode)) + postfix,
        'category': category('1vm-%s' % runtime),
        'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
        'platform': 'posix' + postfix,
      })

  for i in [1, 2, 3, 4]:
    variants_vm_recipe.append({
      'name': ('vm-precomp-win-simarm64-%s-4' % i) + postfix,
      'category': category('1vm-precomp'),
      'factory_builder': annotator.BaseFactory(
          recipe='dart/dart',
          factory_properties={
              'target_arch': 'simarm64',
              'build_targets': ['runtime_precompiled'],
              'test_args': ['-cprecompiler', '-rdart_precompiled',
                            '--shard=%s' % i, '--shards=4',
                            '--use-blobs']}),
      'platform': 'posix' + postfix,
    })

  for shard in range(1,6):
    variants_vm_recipe.append({
      'name': ('dart2js-linux-d8-hostchecked-unittest-%s-5' % shard) + postfix,
      'builddir': ('dart2js-linux-d8-hostchecked-%s-5' % shard) + postfix,
      'category': category('20dart2js-d8-hostchecked'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart2js'),
      'platform': 'posix' + postfix,
    })

  for mode in ['debug', 'release']:
    variants_vm_recipe.append({
      'name': ('vm-linux-%s-x64-reload' % mode) + postfix,
      'category': category('1vm-reload'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
      'platform': 'posix' + postfix,
    })
    variants_vm_recipe.append({
      'name': ('vm-linux-%s-x64-reload-rollback' % mode) + postfix,
      'category': category('1vm-reload'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
      'platform': 'posix' + postfix,
    })
    variants_vm_recipe.append({
      'name': ('vm-mac-%s-simdbc64-reload' % mode) + postfix,
      'category': category('1vm-reload'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dart_vm'),
      'platform': 'posix' + postfix,
    })

  ####### Dartium integration overrides, we only use the dartium builders there
  if channel.name == 'integration':
    variants_vm_recipe = []
    variants_recipe_special_trigger = []
    variants_kernel_recipe = []

  # Add the dartium recipe builders after clearing on the integration branch,
  # so they are also on that branch.
  for platform in ['linux', 'mac', 'win']:
    bitness = 'ia32' if platform == 'win' else 'x64'
    variants_vm_recipe.append({
      'name': ('dartium-%s-%s' % (platform, bitness)) + postfix,
      'category': category('97dartium-full'),
      'factory_builder': annotator.BaseFactory(recipe='dart/dartium'),
      'platform': ('windows' if platform == 'win' else 'posix') + postfix,
      'auto_reboot': platform == 'win',
      'builddir': ('dtm%s' % platform) + channel.name[:2],
    })
    if channel.name == 'be' or channel.name == 'integration':
      variants_vm_recipe.append({
        'name': ('dartium-%s-%s-inc' % (platform, bitness)) + postfix,
        'category': category('6dartium-inc'),
        'factory_builder': annotator.BaseFactory(recipe='dart/dartium'),
        'platform': ('windows' if platform == 'win' else 'posix') + postfix,
        'auto_reboot': platform == 'win',
        'builddir': ('dtmi%s' % platform) + channel.name[:2],
      })


  ####### Schedulers

  # builder names
  vm_recipe_builder_names = utils.get_builder_names(variants_vm_recipe)
  kernel_recipe_builder_names = utils.get_builder_names(variants_kernel_recipe)

  c['schedulers'].append(Scheduler(
      name='main' + postfix,
      branch=channel.branch,
      treeStableTimer=0,
      builderNames=vm_recipe_builder_names + kernel_recipe_builder_names))

  ####### Builders

  for collection in [variants_kernel_recipe, variants_vm_recipe,
                     variants_recipe_special_trigger]:
    for b in utils.get_builders_from_variants(collection, slaves, []):
      c['builders'].append(b)
# End of setup_channel(channel)

c['builders'] = []
c['schedulers'] = []
for channel in CHANNELS:
  setup_channel(channel)

####### CHANGESOURCES

c['change_source'] = [
    utils.get_github_mirror_poller('dart-lang',
                                   'sdk',
                                   branch='master',
                                   master='main'),
    utils.get_github_mirror_poller('dart-lang',
                                   'sdk',
                                   branch='dev',
                                   master='main'),
    utils.get_github_mirror_poller('dart-lang',
                                   'sdk',
                                   branch='stable',
                                   master='main'),
    utils.get_github_mirror_poller('dart-lang',
                                   'sdk',
                                   branch='integration',
                                   master='main')]

####### BUILDSLAVES

c['slaves'] = utils.get_slaves(c['builders'])

# Make sure everything works together.
master_utils.VerifySetup(c, slaves)

# Prioritize the builders depending on channel.
c['prioritizeBuilders'] = utils.prioritize_builders

####### STATUS TARGETS

# 'status' is a list of Status Targets. The results of each build will be
# pushed to these targets. buildbot/status/*.py has a variety to choose from,
# including web pages, email senders, and IRC bots.

c['status'] = [status_logger.StatusEventLogger()]

# Add in the pubsub pusher, which pushes all status updates to a pubsub
# topic.  This will not run unless is_production_host is set to True.
# This will fail on a production host if it cannot find the service
# account file.
pubsub_pusher = pubsub_json_status_push.StatusPush.CreateStatusPush(
    activeMaster=ActiveMaster)
if pubsub_pusher:
  c['status'].append(pubsub_pusher)

if WEB_STATUS:
  for status in utils.get_web_statuses():
    c['status'].append(status)

if MAIL_NOTIFIER:
  # We have people that are interested in a specific subset of the builders
  # and want to be notified whenever they break.
  mail_notifiers = [
    {
      'extraRecipients': ['whesse+botfailures@google.com',],
      'builders': None,  # None means all builders
      'sendToInterestedUsers': True,
    },
    {
      'extraRecipients': ['ricow@google.com', 'whesse@google.com',
                          'kasperl@google.com'],
      'builders': ['version-checker-dev', 'version-checker-stable'],
      'subject': 'VERSION file breakage - bad build',
      'sendToInterestedUsers': True,
    }
  ]

  for notifier in utils.get_mail_notifier_statuses(mail_notifiers):
    c['status'].append(notifier)

if GOOD_REVISIONS:
  from master import goodrevisions
  # We use this basically to decide if the vm in release mode, dart2js on d8,
  # and dartium inc succeeded.
  factory_map = []
  def is_important(name):
    # Only bleeding edge builds matter
    if not name.endswith('-be'):
      return False
    # Linux vm and dart2js v8 bots
    important = ['vm-linux-release-ia32', 'vm-linux-release-x64',
                 'dart2js-linux-release-minified']
    for prefix in important:
      if name.startswith(prefix):
        return True
    if 'dartium' in name and '-inc' in name:
      return True

  for b in c['builders']:
    if is_important(b['name']):
      factory_map.append((b['name'], b['factory']))

  log.msg("LKGR based on: %s " % [b[0] for b in factory_map])

  any_steps = build_utils.ExtractFactoriesSteps(factory_map)
  c['status'].append(goodrevisions.GoodRevisions(
      good_revision_steps=any_steps,
      store_revisions_url=ActiveMaster.store_revisions_url))


# Keep last build logs, the default is too low.
c['buildHorizon'] = 1000
c['logHorizon'] = 500
# Must be at least 2x the number of slaves.
c['eventHorizon'] = 700

# Template generation is using 40 entries, so give it a little extra.
c['buildCacheSize'] = 42

c['properties'] = {'mastername': master_utils.GetMastername()}

####### PROJECT IDENTITY

# the 'projectName' string will be used to describe the project that this
# buildbot is working on. For example, it is used as the title of the
# waterfall HTML page. The 'projectURL' string will be used to provide a link
# from buildbot HTML pages to your project's home page.

c['projectName'] = ActiveMaster.project_name
c['projectURL'] = config.Master.project_url

# the 'buildbotURL' string should point to the location where the buildbot's
# internal web server (usually the html.Waterfall page) is visible. This
# typically uses the port number set in the Waterfall 'status' entry, but
# with an externally-visible host name which the buildbot cannot figure out
# without some help.

c['buildbotURL'] = ActiveMaster.buildbot_url
